package com.hontech.bread.api

import com.hontech.bread.R
import com.hontech.bread.device.DeviceStatus
import com.hontech.bread.store.Order
import com.hontech.bread.store.StoreCargo
import com.hontech.bread.store.StoreProduct
import com.hontech.bread.store.StoreProductExt
import com.hontech.bread.utils.currentTimestamp
import com.hontech.bread.utils.execIgnore
import com.hontech.bread.utils.globalJson
import com.hontech.bread.utils.log
import com.hontech.bread.utils.macAddr
import com.hontech.bread.utils.parsePrice
import com.hontech.bread.utils.priceFormat2
import com.hontech.bread.utils.runCPU
import com.hontech.bread.utils.runIO
import com.hontech.bread.utils.runOnUiCatchAny
import com.hontech.bread.utils.stringById
import kotlinx.coroutines.delay
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
import java.util.TreeSet
import java.util.concurrent.TimeUnit


private const val BASE_URL = "http://hfrd.hontech-rdcenter.com:8080/hontechgroup"
private const val BASE_URL2 = "http://cm6kjw.natappfree.cc/bg-uc"

private val client = OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .writeTimeout(10, TimeUnit.SECONDS)
    .build()

private val MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()


private fun doGet(url: String): ByteArray {
    val req = Request.Builder()
        .get()
        .url(url)
        .build()
    val resp = client.newCall(req).execute()
    return resp.body?.bytes() ?: throw IllegalStateException("no body")
}

suspend fun downloadImage(url: String) = runIO { doGet(url) }

@Serializable
private class ServerResponse<T>(
    val code: Int,
    val msg: String,
    val data: T,
)

@Serializable
private class ProductConfig(

    @SerialName("goodsId")
    val productId: String,

    @SerialName("goods")
    val name: String,

    @SerialName("recars")
    val cargo: String,

    @SerialName("img")
    val imageUrl: String? = null,

    @SerialName("price")
    val price: String,

    @SerialName("infraredheating")
    val heatTime: String? = null,

    @SerialName("quaGuaPeriod")
    val expirationDay: Int? = null
) {

    fun isValid(): Boolean {
        return name.isNotEmpty() &&
                productId.isNotEmpty() &&
                (imageUrl?.isNotEmpty() ?: false) &&
                (heatTime?.isNotEmpty() ?: false) &&
                (expirationDay != null)
    }

    fun convert(): ServerProduct {
        if (name.isEmpty()
            || productId.isEmpty()
            || imageUrl.isNullOrEmpty()
            || (heatTime == null)
            || (expirationDay == null)
        ) {
            throw IllegalStateException(stringById(R.string.t1733460848_8))
        }

        val ls = cargo.split("-")
        val col = ls[0].toInt()
        val row = ls[1].toInt()

        return ServerProduct(
            productId,
            name,
            col,
            row,
            imageUrl,
            parsePrice(price),
            heatTime.toInt(),
            expirationDay * 24 * 3600L
        )
    }
}

private suspend fun productConfigByServer(): List<ProductConfig> {
    val body = runIO { doGet("$BASE_URL/rocars/get/${macAddr}/product") }
    return runCPU {
        val bodyStr = String(body)
        log("${stringById(R.string.t1733460848_9)}:${bodyStr}")
        val resp = globalJson.decodeFromString<ServerResponse<List<ProductConfig>>>(bodyStr)
        resp.data
    }
}

private class ServerProduct(
    val productId: String,
    val name: String,
    val col: Int,
    val row: Int,
    val imageUrl: String,
    val price: Int,
    val heatTime: Int,
    val expiration: Long
)


suspend fun productInitByServer() {
    val productConfigs = productConfigByServer()
    val productIdSet = TreeSet<String>()
    val pes = ArrayList<StoreProductExt>()

    for (pc in productConfigs) {

        if (!pc.isValid()) {
            continue
        }

        execIgnore {
            val product = pc.convert()
            if (!productIdSet.contains(product.productId)) {
                val sp = StoreProductExt(
                    product.productId,
                    product.name,
                    product.price,
                    product.heatTime,
                    product.expiration,
                    product.imageUrl
                )
                pes.add(sp)
                productIdSet.add(product.productId)
            }
            log("${stringById(R.string.t1733460848_10)}:${product.name} ${product.col}-${product.row}")
            StoreCargo.setProduct(product.col, product.row, product.productId)
        }
    }

    StoreProduct.update(pes)
}

@Serializable
private class UploadStockInfoReq(
    @SerialName("macAddr")
    val macAddress: String,
    val stocks: List<StoreCargo.Companion.StockInfo>
)

suspend fun uploadStock() {
    val stock = StoreCargo.queryStock()
    val json = runCPU { globalJson.encodeToString(UploadStockInfoReq(macAddr, stock)) }
    log("${stringById(R.string.t1733460848_11)}:$json")

    runIO {
        val req = Request.Builder()
            .post(json.toRequestBody(MEDIA_TYPE))
            .url("$BASE_URL/replenishment/bread/stock")
            .build()
        val resp = client.newCall(req).execute()
        if (!resp.isSuccessful) {
            throw IllegalStateException("${stringById(R.string.t1733460848_12)}")
        }
    }

}

@Serializable
private class UploadOrder(
    @SerialName("waresName")
    val name: String,
    @SerialName("waresId")
    val productId: String,
    @SerialName("sign")
    val sign: Int,
    @SerialName("payTimestamp")
    val payTimestamp: Long,
    @SerialName("cargo")
    val cargo: String,
    @SerialName("price")
    val price: String,
    @SerialName("remark")
    val remark: String,
)

@Serializable
private class UploadOrderReq(
    @SerialName("macAddr")
    val macAddress: String,
    @SerialName("orders")
    val orders: List<UploadOrder>,
)

suspend fun uploadOrder() {
    val orders = Order.query()
    if (orders.isEmpty()) {
        log(stringById(R.string.t1733460848_13))
        return
    }

    val json = runCPU {
        val uploadOrders = orders.map {
            val sign = if (it.remark == Order.REMARK_SUCC) 1 else 0
            val remark = if (it.remark == Order.REMARK_SUCC) {
                "${stringById(R.string.t1733460848_14)}:${priceFormat2(it.coin.toLong())} " +
                        "${stringById(R.string.t1733460848_15)}:${priceFormat2(it.bill.toLong())} " +
                        "Pos:${priceFormat2(it.pos.toLong())} " +
                        "${stringById(R.string.t1733460848_16)}:${priceFormat2(it.change.toLong())}"
            } else {
                it.remark
            }
            UploadOrder(
                it.name,
                it.productId,
                sign,
                it.createTimestamp,
                it.cargo,
                priceFormat2(it.price.toLong()),
                remark
            )
        }
        globalJson.encodeToString(UploadOrderReq(macAddr, uploadOrders))
    }

    log("${stringById(R.string.t1733460848_17)}:${json}")

    runIO {
        val req = Request.Builder()
            .post(json.toRequestBody(MEDIA_TYPE))
            .url("$BASE_URL/order/save")
            .build()
        val resp = client.newCall(req).execute()
        if (!resp.isSuccessful) {
            throw IllegalStateException(stringById(R.string.t1733460848_18))
        }
    }

    for (order in orders) {
        order.delete()
    }
}


fun startUploadStatus() {
    runOnUiCatchAny {
        delay(5 * 1000)

        var count = 0

        while (true) {

            upload(count)

            count += 1

            delay(3 * 60 * 1000)
        }
    }
}

@Serializable
private class Status(
    val temp: Int,
    val eqCounter: Int,
    val eqTime: Long,
)

@Serializable
private class StatusReq(
    val macAddr: String,
    val eqTemp: Status,
)

private suspend fun upload(count: Int) = runIO {


    val s = DeviceStatus.get()

    val req = StatusReq(
        macAddr,
        Status(
            s.pt100,
            count,
            currentTimestamp()
        )
    )

    val body = globalJson.encodeToString(req)
    log("状态:$body")

    val request = Request.Builder()
        .post(body.toRequestBody(MEDIA_TYPE))
        .url("$BASE_URL/status/save/eqtemp")
        .build()

    val resp = client.newCall(request).execute()
    if (!resp.isSuccessful) {
        throw IOException("upload error:${resp.code} ${resp.message}")
    }

}

















